<?php

declare(strict_types=1);

namespace JsonDb\JsonDb;

/**
 * 主数据库类 - 提供CRUD核心功能
 * 
 * 职责：
 * 1. 数据表管理
 * 2. 数据插入/更新
 * 3. 查询执行
 * 4. 数据删除
 */
class JsonDb
{
	/** @var FileHandler 文件处理器实例 */
	private FileHandler $fileHandler;

	/** @var QueryBuilder 查询构建器实例 */
	private QueryBuilder $queryBuilder;

	/** @var array 数据库配置 */
	private array $config;

	/**
	 * 构造函数
	 * 
	 * @param array $config 数据库配置
	 * @throws \InvalidArgumentException 当缺少必要配置时抛出
	 */
	public function __construct(array $config = [])
	{
		// 合并默认配置
		$this->config = array_merge([
			'path' => null,          // 必须：存储目录路径
			'prefix' => '',           // 表前缀
			'file_suffix' => '.json', // 文件后缀
			'auto_timestamp' => true // 自动添加时间戳
		], $config);

		// 验证必要配置
		if (empty($this->config['path'])) throw new \InvalidArgumentException("必须配置数据存储路径");
	}

	/**
	 * 选择数据表
	 * 
	 * @param string $tableName 表名（不带前缀）
	 * @return self
	 */
	public function table(string $tableName): self
	{
		// 验证表名合法性
		$this->validateTableName($tableName);

		// 构建完整文件路径
		$fullPath = $this->buildTablePath($tableName);

		// 初始化文件处理器和查询构建器
		$this->fileHandler = new FileHandler($fullPath);
		$this->queryBuilder = new QueryBuilder();

		return $this;
	}

	/**
	 * 插入新记录
	 * 
	 * @param array $data 要插入的数据
	 * @return int 新插入记录的ID
	 */
	public function insert(array $data): int
	{
		// 读取现有数据
		$records = $this->fileHandler->read();

		// 预处理数据（添加ID、时间戳等）
		$data = $this->prepareData($data);

		// 添加新记录
		$records[] = $data;

		// 写回文件
		$this->fileHandler->write($records);

		return $data['id'];
	}

	public function update(array $data): int
	{
		$records = $this->fileHandler->read();
		$filtered = $this->queryBuilder->apply($records);

		foreach ($filtered as $index) {
			$records[$index] = array_merge($records[$index], $this->prepareData($data, false));
		}

		$this->fileHandler->write($records);
		return count($filtered);
	}

	public function select(): array
	{
		return $this->queryBuilder->apply($this->fileHandler->read());
	}

	public function delete(): int
	{
		$records = $this->fileHandler->read();
		$filtered = $this->queryBuilder->apply($records);
		$remaining = array_diff_key($records, array_flip(array_keys($filtered)));
		$this->fileHandler->write($remaining);
		return count($records) - count($remaining);
	}

	/**
	 * 数据预处理
	 * 
	 * @param array $data 原始数据
	 * @param bool $isNew 是否是新增记录
	 * @return array 处理后的数据
	 */
	private function prepareData(array $data, bool $isNew = true): array
	{
		// 自动添加时间戳
		if ($this->config['auto_timestamp']) {
			$now = (new \DateTime())->format(\DateTimeInterface::ATOM);
			$data['created_time'] = $isNew ? $now : ($data['created_time'] ?? $now);
			$data['updated_time'] = $now;
		}

		// 生成自增ID
		if ($isNew) $data['id'] = $this->generateId();

		return $data;
	}


	private function generateId(): int
	{
		$records = $this->fileHandler->read();
		$ids = array_column($records, 'id');
		return $ids ? max($ids) + 1 : 1;
	}

	private function buildTablePath(string $tableName): string
	{
		return rtrim($this->config['path'], '/\\')
			. DIRECTORY_SEPARATOR
			. $this->config['prefix']
			. $tableName
			. $this->config['file_suffix'];
	}

	private function validateTableName(string $name): void
	{
		if (!preg_match('/^[a-zA-Z0-9_]+$/', $name)) {
			throw new \InvalidArgumentException("非法表名: $name");
		}
	}

	// 以下方法保持链式调用
	public function where(string $field, string $operator, $value): self
	{
		$this->queryBuilder->where($field, $operator, $value);
		return $this;
	}

	public function orderBy(string $field, string $direction = 'ASC'): self
	{
		$this->queryBuilder->orderBy($field, $direction);
		return $this;
	}

	public function limit(int $offset, ?int $length = null): self
	{
		$this->queryBuilder->limit($offset, $length);
		return $this;
	}
}
